﻿using System;
using System.Windows;
using System.Windows.Input;
using SharpDX;

namespace RPGOnlineWPF.Renderer
{
	public class OrthoCamera : BaseCamera
	{
		private readonly UIElement m_ui;
		private Matrix m_lastWorldViewProjMatrix;
		private Matrix m_lastViewMatrix;

		public OrthoCamera(UIElement ui)
		{
			m_ui = ui;
			m_viewMat = Matrix.Identity;

			UpdateProj();
			UpdateView();
		}

		public override void FrameMove(TimeSpan elapsed)
		{
		}

		protected override void UpdateProj()
		{
			if (m_ui == null)
				return;
			m_projMat = Matrix.OrthoOffCenterLH(0, (float)((m_ui.RenderSize.Width * 1.5f) / 32f), (float)((m_ui.RenderSize.Height * 1.5f) / 32f), 0, 0, 1);
		}

		public override Vector2 GetVector(UIElement ui, MouseEventArgs e)
		{
			var p = e.GetPosition(ui);
			var coord = new Vector3((float) p.X, (float) p.Y, 0);
			return GetVector(coord);
		}

		protected Vector2 GetVector(Vector3 coord)
		{
			coord = Vector3.Unproject(coord, 0, 0, (float)m_ui.RenderSize.Width, (float)m_ui.RenderSize.Height, 0, 1, m_lastWorldViewProjMatrix);
			return new Vector2(coord.X, coord.Y);
		}

		public override Vector2 Project(Vector4 worldPoint)
		{
			var projectedPoint = Vector3.Project(new Vector3(worldPoint.X, worldPoint.Y, worldPoint.Z), 0, 0, (float)m_ui.RenderSize.Width, (float)m_ui.RenderSize.Height, 0, 1, m_lastWorldViewProjMatrix);
			return new Vector2(projectedPoint.X, projectedPoint.Y);
		}

		protected override void UpdateView()
		{
		}

		public override void HandleMouseDown(UIElement ui, MouseButtonEventArgs e)
		{
			if (e.MiddleButton == MouseButtonState.Pressed)
			{
				m_lastWorldViewProjMatrix = m_viewMat*m_projMat;
				m_lastViewMatrix = m_viewMat;
				base.HandleMouseDown(ui, e);
			}
		}

		public override void HandleMouseMove(UIElement ui, MouseEventArgs e)
		{
			if (e.MiddleButton == MouseButtonState.Pressed)
			{
				var pMouse = GetVector(ui, e);
				var dp = pMouse - m_mouseDownPos;

				m_viewMat = Matrix.Translation(dp.X, dp.Y, 0) * m_lastViewMatrix;

				m_mouseLastPos = pMouse;
			}
		}

		public override void HandleMouseUp(UIElement ui, MouseButtonEventArgs e)
		{
			m_lastWorldViewProjMatrix = m_viewMat * m_projMat;
		}

		public override void HandleMouseWheel(UIElement ui, MouseWheelEventArgs e)
		{
			var pMouse = GetVector(ui, e);
			var pCenter = GetVector(new Vector3((float) (ui.RenderSize.Width/2), (float) (ui.RenderSize.Height/2), 0));
			var distanceFromCenter = pCenter - pMouse;

			var dp = e.Delta > 0 ? 1.1f : 0.9f;
			m_viewMat = Matrix.Translation(distanceFromCenter.X, distanceFromCenter.Y, 0) * Matrix.Scaling(dp, dp, 1) * Matrix.Translation(-distanceFromCenter.X, -distanceFromCenter.Y, 0) * m_viewMat;

			m_lastWorldViewProjMatrix = m_viewMat * m_projMat;
			m_lastViewMatrix = m_viewMat;
		}
	}
}